package com.whiteape.book.utils;

import android.net.Uri;

import com.kunfei.bookshelf.bean.BookSourceBean;
import com.whiteape.book.model.dto.SiteSourceBean;
import com.whiteape.book.model.dto.SiteSourceChapterInfoBean;
import com.whiteape.book.model.dto.SiteSourceContentInfoBean;
import com.whiteape.book.model.dto.SiteSourceMediaInfoBean;
import com.whiteape.book.model.dto.SiteSourceSearchBean;
import com.whiteape.book.model.dto.SiteSourceSearchResultBean;
import com.whiteape.book.model.type.MediaType;
import com.whiteape.book.model.type.SourceFromType;

import org.json.JSONArray;
import org.json.JSONObject;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.legado.app.data.entities.BookSource;

public enum YueduSourceConverter {

    INSTANCE;

    final private Pattern pattern = Pattern.compile("\\.(\\d+)");

    public List<SiteSourceBean> convert(String source) {

        List<SiteSourceBean> beanList = new ArrayList<>();
        try {
            if (!source.contains("bookSourceUrl")) {
                return beanList;
            }
            source = source.trim();
            //去掉bom头
            if (source.startsWith("\ufeff")) {
                source = source.substring(1);
            }
            if (source.startsWith("[")) {
                JSONArray jsonArr = new JSONArray(source);
                for(int i =0; i < jsonArr.length(); i++){
                    JSONObject jsonobj = jsonArr.getJSONObject(i);
                    if(jsonobj.has("ruleSearchUrl")){
                        //yuedu 2.0
                        BookSourceBean bookSourceBean = GsonUtils.string2Obj(jsonobj.toString(),BookSourceBean.class);
                        //1表示有声  0表示小说
                        if(bookSourceBean.getBookSourceType() != null && bookSourceBean.getBookSourceType().equals("1")){
                            continue;
                        }
                        beanList.add(convertYuedu2ToSiteSourceBean(bookSourceBean));
                    }else{
                        BookSource bookSourceBean = GsonUtils.string2Obj(jsonobj.toString(),BookSource.class);
                        if(bookSourceBean.getBookSourceType() == 1){
                            continue;
                        }
                        beanList.add(convertYuedu3ToSiteSourceBean(bookSourceBean));
                    }
                }

            } else {
                if(source.contains("ruleSearchUrl")) {
                    //yuedu 2.0
                    BookSourceBean bookSourceBean = GsonUtils.string2Obj(source, BookSourceBean.class);
                    beanList.add(convertYuedu2ToSiteSourceBean(bookSourceBean));
                }else{
                    //yuedu 3.0
                    BookSource bookSource = GsonUtils.string2Obj(source, BookSource.class);
                    beanList.add(convertYuedu3ToSiteSourceBean(bookSource));

                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return beanList;
    }

    private SiteSourceBean convertYuedu2ToSiteSourceBean(BookSourceBean bookSourceBean){
        SiteSourceBean siteSourceBean = new SiteSourceBean();
        siteSourceBean.setSiteHostUrl(bookSourceBean.getBookSourceUrl());
        siteSourceBean.setSiteName(bookSourceBean.getBookSourceName());
        siteSourceBean.setSiteType(MediaType.MEDIA_TYPE_NOVEL);
        siteSourceBean.setSiteDesc("外部源");
        siteSourceBean.setCreator("佚名");
        siteSourceBean.setUserAgent(bookSourceBean.getHttpUserAgent());
        siteSourceBean.setSiteIconUrl("");
        siteSourceBean.setSourceFrom(SourceFromType.SOURCE_FROM_YUEDU2);
        siteSourceBean.setExtraSource(GsonUtils.obj2String(bookSourceBean));
        return siteSourceBean;
    }

    private SiteSourceBean convertYuedu3ToSiteSourceBean(BookSource bookSourceBean) throws Exception {
        SiteSourceBean siteSourceBean = new SiteSourceBean();
        siteSourceBean.setSiteHostUrl(bookSourceBean.getBookSourceUrl());
        siteSourceBean.setSiteName(bookSourceBean.getBookSourceName());
        if(bookSourceBean.getRuleContent() != null && "FULL".equals(bookSourceBean.getRuleContent().getImageStyle())){
            siteSourceBean.setSiteType(MediaType.MEDIA_TYPE_COMIC);
        }else{
            siteSourceBean.setSiteType(MediaType.MEDIA_TYPE_NOVEL);
        }
        Map<String, String> headerMap = bookSourceBean.getHeaderMap();
        if(headerMap != null){
            for(String key : headerMap.keySet()){
                if(key.toLowerCase().equals("user-agent")){
                    siteSourceBean.setUserAgent(headerMap.get(key));
                }
            }
        }
        siteSourceBean.setSiteDesc(bookSourceBean.getBookSourceComment());
        siteSourceBean.setCreator("佚名");
        siteSourceBean.setSiteIconUrl("");
        siteSourceBean.setSourceFrom(SourceFromType.SOURCE_FROM_YUEDU3);
        siteSourceBean.setExtraSource(GsonUtils.obj2String(bookSourceBean));
        return siteSourceBean;
    }
    public List<SiteSourceBean> convertOld(String source) {
        List<SiteSourceBean> beanList = new ArrayList<>();
        try {
            if (!source.contains("bookSourceUrl") || !source.contains("ruleBookContent")) {
                return beanList;
            }
            source = source.trim();
            //去掉bom头
            if (source.startsWith("\ufeff")) {
                source = source.substring(1);
            }
            if (source.startsWith("[")) {
                JSONArray array = new JSONArray(source);
                int total = array.length();
                for (int i = 0; i < array.length(); i++) {
                    System.out.println("TOTAL:" + total + " current ok:" + beanList.size());
                    try {
                        JSONObject object = array.getJSONObject(i);
                        String objStr = object.toString();
                        //TODO 引擎中添加 java.get java.put 一个hashmap即可
                        //TODO java.ajax=>java.getUrl
                        //TODO java.base64Decoder
                        //TODO java.getElements ?
                        if (objStr.contains("<js>") || objStr.contains("@json")
                                || objStr.contains("##") || objStr.contains("$.")
                                || objStr.contains("@js") || objStr.contains("java.")
                                || objStr.contains("@put") || objStr.contains("@get")
                        ) {
                            continue;
                        }

                        beanList.add(makeSiteSourceBean(object));

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            } else {
                JSONObject object = new JSONObject(source);
                beanList.add(makeSiteSourceBean(object));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return beanList;
    }

    private SiteSourceBean makeSiteSourceBean(JSONObject object) {

        SiteSourceBean siteSourceBean = new SiteSourceBean();

        makeCommonInfo(object, siteSourceBean);
        makeSearch(object, siteSourceBean);
        makeMediaDetail(object, siteSourceBean);
        makeCatalog(object, siteSourceBean);
        makeContent(object, siteSourceBean);


        return siteSourceBean;
    }

    private SiteSourceBean makeCommonInfo(JSONObject object, SiteSourceBean siteSourceBean) {

        siteSourceBean.setSiteName(object.optString("bookSourceName"));
        siteSourceBean.setSiteHostUrl(object.optString("bookSourceUrl"));
        siteSourceBean.setUserAgent(object.optString("httpUserAgent"));
        siteSourceBean.setSiteType(MediaType.MEDIA_TYPE_NOVEL);
        siteSourceBean.setCreator("佚名");
        siteSourceBean.setSiteDesc("外部转换源");
        return siteSourceBean;
    }

    private SiteSourceBean makeSearch(JSONObject object, SiteSourceBean siteSourceBean) {

        //////////////////////搜索模块
        SiteSourceSearchBean searchBean = new SiteSourceSearchBean();
        String searchUrl = object.optString("ruleSearchUrl");
        searchBean.setUrl(object.optString("ruleSearchUrl"));
        searchBean.setCharset("utf-8");
        Map<String, String> headers = new HashMap<>();
        Map<String, String> params = new HashMap<>();
        searchBean.setHeaders(headers);
        searchBean.setParams(params);
        //提取header    @Header:{sdfsdf:sdfdf}或者@header:{}
        if (searchUrl.toLowerCase().contains("@header:")) {
            int headerIndex = searchUrl.toLowerCase().indexOf("@header");
            int headerStart = searchUrl.indexOf("{", headerIndex);
            int headEnd = searchUrl.indexOf("}", headerIndex);
            String headerStr = searchUrl.substring(headerStart + 1, headEnd);
            String[] headerArr = headerStr.split(",");
            for (String header : headerArr) {
                if (header.contains(":")) {
                    int index = header.indexOf(":");
                    headers.put(header.substring(0, index).replace("'", "").replace("\"", ""),
                            header.substring(index + 1).replace("'", "").replace("\"", ""));
                }
            }
            if (headerIndex == 0) {
                searchUrl = searchUrl.substring(headEnd + 1);
            } else {
                searchUrl = searchUrl.substring(0, headerIndex);
            }
        }
        String[] searchUrlArr = searchUrl.split("\\|");
        if (searchUrlArr.length > 0) {
            searchUrl = searchUrlArr[0];
            String[] charArr = searchUrlArr[1].split("=");
            if (charArr.length > 0) {
                searchBean.setCharset(charArr[1]);
            }
        }
        searchBean.setRequestMethod("GET");
        if (searchUrl.contains("?")) {
            //有?的一般用xxx=searchKey来做
            //TODO  "http://www.xoyo100.org/modules/article/search.php?ie=gbk@searchkey=searchKey&ct=2097152|char=gbk",
            //TODO 上面这种既有?又有@的。。用下面语句替换下。。
            searchUrl.replace("@","&");

            int index = searchUrl.indexOf("?");
//                        String[] urlParts = searchUrl.split("\\?");
            String rest = searchUrl.substring(index + 1);
            searchUrl = searchUrl.substring(0, index);
            for (String each : rest.split("&")) {
                String[] eachParamsArr = each.split("=");
                //不要searchPage
                if (eachParamsArr.length > 1 && !eachParamsArr[1].equals("searchPage")) {
                    params.put(eachParamsArr[0], eachParamsArr[1]);
                }
            }
        } else if (searchUrl.contains("@")) {
            //这里是POST
            searchBean.setRequestMethod("POST");
            int index = searchUrl.indexOf("@");
            String rest = searchUrl.substring(index + 1);
            searchUrl = searchUrl.substring(0, index);
            for (String each : rest.split("&")) {
                String[] eachParamsArr = each.split("=");
                //不要searchPage
                if (eachParamsArr.length > 1 && !eachParamsArr[1].equals("searchPage")) {
                    params.put(eachParamsArr[0], eachParamsArr[1]);
                }
            }
        } else {
            //没有?的一般是RESTFUL /xxx/yyy/searchKey/xad/格式的
            searchUrl = searchUrl.replace("=searchKey", "={{searchKey}}");

        }
        searchBean.setUrl(searchUrl);
        makeSearchResult(object, searchBean, siteSourceBean);
        return siteSourceBean;
    }

    private SiteSourceBean makeSearchResult(JSONObject object, SiteSourceSearchBean searchBean, SiteSourceBean siteSourceBean) {

        SiteSourceSearchResultBean searchResultBean = new SiteSourceSearchResultBean();
        searchResultBean.setTitle(getRule(object.optString("ruleSearchName"), false));
        searchResultBean.setDetailUrl(getRule(object.optString("ruleSearchNoteUrl"), false));
        searchResultBean.setAuthor(getRule(object.optString("ruleSearchAuthor"), false));
        searchResultBean.setList(getRule(object.optString("ruleSearchList"), true));
        searchResultBean.setCategory(getRule(object.optString("ruleSearchKind"), false));
        searchResultBean.setCoverUrl(getRule(object.optString("ruleSearchCoverUrl"), false));
        searchResultBean.setDesc(getRule(object.optString("ruleSearchIntroduce"), false));
        searchResultBean.setLastUpdated("");
        searchResultBean.setLastChapter(getRule(object.optString("ruleSearchLastChapter"), false));

        searchBean.setResult(searchResultBean);
        siteSourceBean.setSearch(searchBean);
        return siteSourceBean;
    }

    private SiteSourceBean makeMediaDetail(JSONObject object, SiteSourceBean siteSourceBean) {
        ///////////////// 详情页解析
        SiteSourceMediaInfoBean mediaInfoBean = new SiteSourceMediaInfoBean();
        mediaInfoBean.setAuthor(getRule(object.optString("ruleBookAuthor"), false));
        mediaInfoBean.setCoverUrl(getRule(object.optString("ruleCoverUrl"), false));
        mediaInfoBean.setDesc(getRule(object.optString("ruleIntroduce"), false));
        mediaInfoBean.setLastChapter(getRule(object.optString("ruleBookLastChapter"), false));
        mediaInfoBean.setCategory(getRule(object.optString("ruleBookKind"), false));
        mediaInfoBean.setTitle(getRule(object.optString("ruleBookName"), false));
        mediaInfoBean.setCatalogUrl(getRule(object.optString("ruleChapterUrl"), false));
        mediaInfoBean.setCatalogNextPageUrl(getRule(object.optString("ruleChapterUrlNext"), false));
        siteSourceBean.setMediaInfoDetailRule(mediaInfoBean);
        return siteSourceBean;
    }

    private SiteSourceBean makeCatalog(JSONObject object, SiteSourceBean siteSourceBean) {
        ///////////////目录解析
        SiteSourceChapterInfoBean chapterInfoBean = new SiteSourceChapterInfoBean();
        chapterInfoBean.setList(getRule(object.optString("ruleChapterList"), true));
        chapterInfoBean.setUrl(getRule(object.optString("ruleContentUrl"), false));
        chapterInfoBean.setName(getRule(object.optString("ruleChapterName"), false));

        siteSourceBean.setChapterInfoRule(chapterInfoBean);
        return siteSourceBean;
    }

    private SiteSourceBean makeContent(JSONObject object, SiteSourceBean siteSourceBean) {
        //////////////内容解析
        SiteSourceContentInfoBean contentInfoBean = new SiteSourceContentInfoBean();
        contentInfoBean.setContent(getRule(object.optString("ruleBookContent"), false));
        contentInfoBean.setPageNext(getRule(object.optString("ruleContentUrlNext"), false));
        siteSourceBean.setContentInfoRule(contentInfoBean);
        return siteSourceBean;
    }
    //TODO  <js> </js> 和 @js: baseUrl-> $url, result->$content
    //TODO https://cdn.jsdelivr.net/gh/yeyulingfeng01/yuedu.github.io@1.1/202003.txt
    //TODO 适配 http://gaoduan.szjinruixin.com/yushuge/index/index.html
    //TODO 适配 @get和@put ,一个句子可能多有个@get ,put的时候可能有"bookTitle@put:{book:bookId}" jsonpath格式的，里面不需要引号，其他比如 @put:{book:'tag.a@text'}这里是需要引号的
    //TODO 适配 {{}} 应该是@JS:

    //如果不是句首，需要添加 |||@JS:
    private String getRule(String rule, boolean isList) {
        StringBuilder retBuilder = new StringBuilder();
        String replaceRule = "";
        //TODO ##xxx##yyy### 这种格式的还有。。。
        int replaceStart = rule.indexOf("#");
        if (replaceStart > 0) {
            replaceRule = rule.substring(replaceStart + 1);
            rule = rule.substring(0, replaceStart);
        }
        String[] splitCharsArr = new String[]{"\\|\\|", "\\|", "&&", "&"};
        String subRule = "";
        boolean hasSplit = false;
        for (String splitChars : splitCharsArr) {
            String[] subRules = rule.split(splitChars);
            if (subRules.length == 1) {
                continue;
            }
            hasSplit = true;
            try {
                for (int i = 0; i < subRules.length; i++) {
                    subRule = subRules[i];
                    subRule = getSubRule(subRule, isList);
                    retBuilder.append(subRule);
                    if (i < subRules.length - 1) {
                        if (splitChars.contains("|")) {
                            //阅读里面的List的是| , 单项的是||，对应白猿都是||
                            retBuilder.append("||");
                        } else if (splitChars.contains("&")) {
                            retBuilder.append("&&");
                        }
                    }
                }
                break;
            } catch (Exception e) {
                continue;
            }
        }
        if (!hasSplit) {
            try {
                return getSubRule(rule, isList);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        //TODO 还有好几种替代方法 ##xxx##xxxxx###
//        if (replaceRule.length() > 0) {
//            retBuilder.append("||| @JS:$content.replace(/").append(replaceRule).append("/,'')");
//        }

        return retBuilder.toString();
    }

    private String getSubRule(String subRule, boolean isList) throws Exception {
        if (subRule.trim().length() == 0 || subRule.trim().toLowerCase().startsWith("@css:")) {
            return subRule;
        }
        subRule = subRule.replaceAll("@tag\\.", " ")
                .replaceAll("^tag\\.", "")
                .replaceAll("^id\\.", "#")
                .replaceAll("@id\\.", " #")
                .replaceAll("^class", "")
                .replaceAll("@class", " ")
        .replaceAll("^text\\.","")
        ;
        Matcher matcher = pattern.matcher(subRule);
        StringBuffer sb = new StringBuffer();
        //.2 和.-2是不一样的表达式
        while (matcher.find()) {
            String d = matcher.group();
            int num = Integer.parseInt(d.substring(1));
            if (num >= 0) {
                matcher.appendReplacement(sb, ":nth-child(" + (num+1) + ")");
            } else {
                matcher.appendReplacement(sb, "nth-last-child(n " + num + ")");
            }
        }
        matcher.appendTail(sb);
        subRule = sb.toString();

        //如果是list，最后需要判断 !2:3之类
        //如果不是list,最后的需要保留 @text @src之类
        String lastGetValueRule = "";
        int lastAtIndex = subRule.lastIndexOf("@");
        if (!isList && lastAtIndex <= 0) {
//            throw new Exception("not list and do not has a @");
            return "@" + subRule;
        }
        if (!isList) {
            lastGetValueRule = subRule.substring(lastAtIndex);
        }

        //!操作只会出现在List中，比如搜索结果列表，章节列表等
        //如果出现在单项rule里面，直接去掉（应该是源有误)
        int operatorNotIndex = subRule.indexOf("!");
        if (operatorNotIndex > 0) {
            String tail = subRule.substring(operatorNotIndex);
            subRule = subRule.substring(0, operatorNotIndex);
            //列表类才解析!，其他的单项，直接截断就行
            if (isList) {
                int index = tail.lastIndexOf(":");
                String lastNumber;
                if (tail.indexOf(":") > 0) {
                    //!1:3:4这种
                    lastNumber = tail.substring(index + 1);
                } else {
                    //!3 这种
                    lastNumber = tail.substring(1);
                }
                int lastNum = Integer.parseInt(lastNumber);
                if (lastNum >= 0) {
                    subRule += ":gt(" + lastNum + ")";
                } else {
                    subRule += ":nth-child(n" + lastNum + ")";
                }
            }
        }

        if (isList) {
            subRule = subRule.replaceAll("@", ">");
        } else {
            //不是list的话要保留最后一个@的获取value的规则
            subRule = subRule.substring(0, lastAtIndex).replaceAll("@", ">") + lastGetValueRule;
        }
        return subRule;
    }
}

